home *** CD-ROM | disk | FTP | other *** search
- /**************************************************************************
- *
- * Copyright (c) 1993 Silicon Graphics, Inc.
- * All Rights Reserved
- *
- * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SGI
- *
- * The copyright notice above does not evidence any actual of intended
- * publication of such source code, and is an unpublished work by Silicon
- * Graphics, Inc. This material contains CONFIDENTIAL INFORMATION that is
- * the property of Silicon Graphics, Inc. Any use, duplication or
- * disclosure not specifically authorized by Silicon Graphics is strictly
- * prohibited.
- *
- * RESTRICTED RIGHTS LEGEND:
- *
- * Use, duplication or disclosure by the Government is subject to
- * restrictions as set forth in subdivision (c)(1)(ii) of the Rights in
- * Technical Data and Computer Software clause at DFARS 52.227-7013,
- * and/or in similar or successor clauses in the FAR, DOD or NASA FAR
- * Supplement. Unpublished - rights reserved under the Copyright Laws of
- * the United States. Contractor is SILICON GRAPHICS, INC., 2011 N.
- * Shoreline Blvd., Mountain View, CA 94039-7311
- **************************************************************************
- *
- * File: impRowIO.c
- *
- * Description: Image row read and write routines.
- *
- **************************************************************************/
-
-
- #ident "$Revision: 1.6 $"
-
-
- #include <stdio.h>
- #include <sys/types.h>
- #include <assert.h>
- #include "impI.h"
-
-
- /* Local functions */
-
- static int rleGetRowSize(IMPImage *image, ushort_t row, ushort_t channel);
- static int rleSetRowSize(IMPImage *image, long count, ushort_t row,
- ushort_t channel);
- static void rleExpandRow(short *rleBuf, int ibpp, short *expBuf, int obpp);
- static int rleCompactRow(short *expBuf, int ibpp, short *rleBuf, int obpp,
- int npixels);
-
-
- /**************************************************************************
- *
- * Function: impWriteRow
- *
- * Description: Writes the specified image data as the specified row and
- * channel.
- *
- * Parameters:
- * image (I) - image to write
- * buffer (I) - data to write
- * row (I) - image row to write
- * channel (I) - image channel to write
- *
- * Return: Number of pixels written if no error. -1 and IMPerrno set if
- * errors.
- *
- **************************************************************************/
-
- int impWriteRow(IMPImage *image, short *buffer, ushort_t row, ushort_t channel) {
- register long vmin, vmax;
- register ushort_t x;
- register short *sptr;
- int count, retv;
-
- /*
- * Sanity check the inputs
- */
- assert(image != NULL);
- assert(buffer != NULL);
-
- /*
- * Verify we can write image
- */
- if (!_impWriting(image))
- _impReturnError(IMP_ERR_WRITEFLAG);
-
- /*
- * Use image dimension to sanitize the row and channel values
- */
- if (impDimension(image) < 3)
- channel = 0;
- if (impDimension(image) < 2)
- row = 0;
-
- /*
- * Determine the min and max image data values. Note that
- * for 1 BPP we are packing the data as uchar into tmpbuf.
- * We can just write this for the 1 BPP VERBATIM case.
- */
- vmin = impMinValue(image);
- vmax = impMaxValue(image);
- sptr = buffer;
- switch (impRasterBPP(image)) {
- case 1:
- {
- register uchar_t *cptr = (uchar_t*)image->tmpbuf;
- for (x = impXSize(image); x--; ) {
- *cptr = (uchar_t)(*sptr++);
- /* LINTED */
- if (*cptr > vmax) vmax = *cptr;
- /* LINTED */
- if (*cptr < vmin) vmin = *cptr;
- cptr++;
- }
- }
- break;
- case 2:
- for (x = impXSize(image); x--; ) {
- /* LINTED */
- if ((unsigned short)*sptr > vmax)
- vmax = (unsigned short)*sptr;
- /* LINTED */
- if ((unsigned short)*sptr < vmin)
- vmin = (unsigned short)*sptr;
- sptr++;
- }
- break;
- default:
- _impReturnError(IMP_ERR_BADBPP);
- }
- impMinValue(image) = vmin;
- impMaxValue(image) = vmax;
-
- /*
- * Go to the appropriate position in the file and
- * write the image data according to its raster encoding
- * and bytes per pixel
- */
- if (impIsVERBATIM(image)) {
- if (_impSeekRow(image, row, channel) < 0)
- _impReturnError(IMPerrno);
- switch (impRasterBPP(image)) {
- case 1:
- if ((retv = _impWrite(image, image->tmpbuf, impXSize(image)))
- != impXSize(image))
- _impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTWRITE);
- return impXSize(image);
- case 2:
- count = impXSize(image) << 1;
- if (image->dorev)
- _impSwapShorts((ushort_t*)buffer, count);
- retv = _impWrite(image, buffer, count);
- if (image->dorev)
- _impSwapShorts((ushort_t*)buffer, count);
- if (retv != count)
- _impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTWRITE);
- return impXSize(image);
- }
- } else if (impIsRLE(image)) {
- switch (impRasterBPP(image)) {
- case 1:
- count = rleCompactRow(buffer, 2, image->tmpbuf, 1,
- impXSize(image));
- if (rleSetRowSize(image, count, row, channel) < 0)
- _impReturnError(IMPerrno);
- if (_impSeekRow(image, row, channel) < 0)
- _impReturnError(IMPerrno);
- if ((retv = _impWrite(image, image->tmpbuf, count)) != count)
- _impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTWRITE);
- return impXSize(image);
- case 2:
- count = rleCompactRow(buffer, 2, image->tmpbuf, 2,
- impXSize(image)) << 1;
- if (rleSetRowSize(image, count, row, channel) < 0)
- _impReturnError(IMPerrno);
- if (_impSeekRow(image, row, channel) < 0)
- _impReturnError(IMPerrno);
- if (image->dorev)
- _impSwapShorts((ushort_t*)image->tmpbuf, count);
- retv = _impWrite(image, image->tmpbuf, count);
- if (image->dorev)
- _impSwapShorts((ushort_t*)image->tmpbuf, count);
- if (retv != count)
- _impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTWRITE);
- return impXSize(image);
- }
- }
-
- _impReturnError(IMP_ERR_BADIMAGE);
- }
-
-
- /**************************************************************************
- *
- * Function: impWriteRowB
- *
- * Description: Writes the specified image data as the specified row and
- * channel. The data buffer for this function is of type unsigned
- * char. This eliminates the need to do copying for 1 BPP images.
- * Note that the image must be 1 BPP or an error is returned.
- *
- * Parameters:
- * image (I) - image to write
- * buffer (I) - data to write
- * row (I) - image row to write
- * channel (I) - image channel to write
- *
- * Return: Number of pixels written if no error. -1 and IMPerrno set if
- * errors.
- *
- **************************************************************************/
-
- int impWriteRowB(IMPImage *image, uchar_t *buffer, ushort_t row,
- ushort_t channel)
- {
- register long vmin, vmax;
- register ushort_t x;
- register uchar_t *cptr;
- int count, retv;
-
- /*
- * Sanity check the inputs
- */
- assert(image != NULL);
- assert(buffer != NULL);
-
- /*
- * Verify that the image is 1 BPP
- */
- if (impRasterBPP(image) != IMP_RASTER_BPP1)
- _impReturnError(IMP_ERR_BADBPP);
-
- /*
- * Verify we can write image
- */
- if (!_impWriting(image))
- _impReturnError(IMP_ERR_WRITEFLAG);
-
- /*
- * Use image dimension to sanitize the row and channel values
- */
- if (impDimension(image) < 3)
- channel = 0;
- if (impDimension(image) < 2)
- row = 0;
-
- /*
- * Determine the min and max image data values.
- */
- vmin = impMinValue(image);
- vmax = impMaxValue(image);
- for (x = impXSize(image), cptr = buffer; x--; cptr++) {
- /* LINTED */
- if (*cptr > vmax) vmax = *cptr;
- /* LINTED */
- if (*cptr < vmin) vmin = *cptr;
- }
- impMinValue(image) = vmin;
- impMaxValue(image) = vmax;
-
- /*
- * Go to the appropriate position in the file and
- * write the image data according to its raster encoding
- * and bytes per pixel
- */
- if (impIsVERBATIM(image)) {
- if (_impSeekRow(image, row, channel) < 0)
- _impReturnError(IMPerrno);
- if ((retv = _impWrite(image, buffer, impXSize(image)))
- != impXSize(image))
- _impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTWRITE);
- return impXSize(image);
- } else if (impIsRLE(image)) {
- /* LINTED */
- count = rleCompactRow((short*)buffer, 1, image->tmpbuf, 1,
- impXSize(image));
- if (rleSetRowSize(image, count, row, channel) < 0)
- _impReturnError(IMPerrno);
- if (_impSeekRow(image, row, channel) < 0)
- _impReturnError(IMPerrno);
- if ((retv = _impWrite(image, image->tmpbuf, count)) != count)
- _impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTWRITE);
- return impXSize(image);
- }
-
- _impReturnError(IMP_ERR_BADIMAGE);
- }
-
-
- /**************************************************************************
- *
- * Function: impReadRow
- *
- * Description: Reads the specified image data as the specified row and
- * channel.
- *
- * Parameters:
- * image (I) - image to read
- * buffer (I) - data to read
- * row (I) - image row to read
- * channel (I) - image channel to read
- *
- * Return: Number of pixels read if no error. -1 and IMPerrno set if
- * errors.
- *
- **************************************************************************/
-
- int impReadRow(IMPImage *image, short *buffer, ushort_t row, ushort_t channel)
- {
- register int count, retv;
-
- /*
- * Sanity check the inputs
- */
- assert(image != NULL);
- assert(buffer != NULL);
-
- /*
- * Verify we can read image
- */
- if (!_impReading(image))
- _impReturnError(IMP_ERR_READFLAG);
-
- /*
- * Use image dimension to sanitize the row and channel values
- */
- if (impDimension(image) < 3)
- channel = 0;
- if (impDimension(image) < 2)
- row = 0;
-
- /*
- * Seek to the specified row and channel and
- * read the image data.
- */
- if (_impSeekRow(image, row, channel) < 0)
- _impReturnError(IMPerrno);
- if (impIsVERBATIM(image)) {
- switch (impRasterBPP(image)) {
- case 1:
- if ((retv = _impRead(image, image->tmpbuf, impXSize(image)))
- != impXSize(image)) {
- _impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTREAD);
- } else {
- register uchar_t *cptr = (uchar_t*)image->tmpbuf;
- register short *sptr = buffer;
- register int i;
- for (i = impXSize(image); i--;)
- *sptr++ = *cptr++;
- }
- return impXSize(image);
- case 2:
- count = impXSize(image) << 1;
- if ((retv = _impRead(image, buffer, count)) != count)
- _impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTREAD);
- if (image->dorev)
- _impSwapShorts((ushort_t*)buffer, count);
- return impXSize(image);
- default:
- _impReturnError(IMP_ERR_BADBPP);
- }
- }
- else if (impIsRLE(image)) {
- switch (impRasterBPP(image)) {
- case 1:
- if ((count = rleGetRowSize(image, row, channel)) < 0)
- _impReturnError(IMPerrno);
- if ((retv = _impRead(image, image->tmpbuf, count)) != count)
- _impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTREAD);
- rleExpandRow(image->tmpbuf, 1, buffer, 2);
- return impXSize(image);
- case 2:
- if ((count = rleGetRowSize(image, row, channel)) < 0)
- _impReturnError(IMPerrno);
- if ((retv = _impRead(image, image->tmpbuf, count)) != count)
- _impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTREAD);
- if (image->dorev)
- _impSwapShorts((ushort_t*)image->tmpbuf, count);
- rleExpandRow(image->tmpbuf, 2, buffer, 2);
- return impXSize(image);
- default:
- _impReturnError(IMP_ERR_BADBPP);
- }
- }
-
- _impReturnError(IMP_ERR_BADIMAGE);
- }
-
-
- /**************************************************************************
- *
- * Function: impReadRowB
- *
- * Description: Reads the specified image data as the specified row and
- * channel. The data buffer for this function is of type unsigned
- * char. This eliminates the need to do copying for 1 BPP images.
- * Note that the image must be 1 BPP or an error is returned.
- *
- * Parameters:
- * image (I) - image to read
- * buffer (I) - data to read
- * row (I) - image row to read
- * channel (I) - image channel to read
- *
- * Return: Number of pixels read if no error. -1 and IMPerrno set if
- * errors.
- *
- **************************************************************************/
-
- int impReadRowB(IMPImage *image, uchar_t *buffer, ushort_t row,
- ushort_t channel)
- {
- register int count, retv;
-
- /*
- * Sanity check the inputs
- */
- assert(image != NULL);
- assert(buffer != NULL);
-
- /*
- * Verify that the image is 1 BPP
- */
- if (impRasterBPP(image) != IMP_RASTER_BPP1)
- _impReturnError(IMP_ERR_BADBPP);
-
- /*
- * Verify we can read image
- */
- if (!_impReading(image))
- _impReturnError(IMP_ERR_READFLAG);
-
- /*
- * Use image dimension to sanitize the row and channel values
- */
- if (impDimension(image) < 3)
- channel = 0;
- if (impDimension(image) < 2)
- row = 0;
-
- /*
- * Seek to the specified row and channel and
- * read the image data.
- */
- if (_impSeekRow(image, row, channel) < 0)
- _impReturnError(IMPerrno);
- if (impIsVERBATIM(image)) {
- if ((retv = _impRead(image, buffer, impXSize(image)))
- != impXSize(image)) {
- _impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTREAD);
- }
- return impXSize(image);
- }
- else if (impIsRLE(image)) {
- if ((count = rleGetRowSize(image, row, channel)) < 0)
- _impReturnError(IMPerrno);
- if ((retv = _impRead(image, image->tmpbuf, count)) != count)
- _impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTREAD);
- /* LINTED */
- rleExpandRow(image->tmpbuf, 1, (short*)buffer, 1);
- return impXSize(image);
- }
-
- _impReturnError(IMP_ERR_BADIMAGE);
- }
-
-
- /*
- =========================================================================
- LOCAL FUNCTIONS
- =========================================================================
- */
-
-
- /**************************************************************************
- *
- * Function: rleGetRowSize
- *
- * Description: Returns the number of bytes in the RLE compressed row
- * for the row and channel specified.
- *
- * Parameters:
- * image (I) - image file
- * row (I) - row whose size is desired
- * channel (I) - channel for the row
- *
- * Return: Row size in bytes if no error. -1 and IMPerrno set if error.
- *
- **************************************************************************/
-
- static int rleGetRowSize(IMPImage *image, ushort_t row, ushort_t channel)
- {
- /*
- * Validate the row and channel inputs
- */
- if (_impBadRow(image, row, channel))
- _impReturnError(IMP_ERR_BADROW);
-
- switch (impDimension(image)) {
- case 1:
- return image->rowsize[0];
- case 2:
- return image->rowsize[row];
- case 3:
- return image->rowsize[row + channel * impYSize(image)];
- default:
- break;
- }
-
- _impReturnError(IMP_ERR_BADDIM);
- }
-
-
- /**************************************************************************
- *
- * Function: rleSetRowSize
- *
- * Description: Sets the number of bytes in the RLE compressed row
- * for the row and channel specified in the appropriate header
- * tables.
- *
- * Parameters:
- * image (I) - image file
- * count (I) - RLE row size in bytes
- * row (I) - row whose size is to be set
- * channel (I) - channel for the row
- *
- * Return: 0 if no error. -1 and IMPerrno set if error.
- *
- **************************************************************************/
-
- static int rleSetRowSize(IMPImage *image, long count, ushort_t row,
- ushort_t channel)
- {
- __int32_t *sizeptr;
-
- /*
- * Validate the row and channel inputs
- */
- if (_impBadRow(image, row, channel))
- _impReturnError(IMP_ERR_BADROW);
-
- switch (impDimension(image)) {
- case 1:
- sizeptr = &image->rowsize[0];
- image->rowstart[0] = image->rleend;
- break;
- case 2:
- sizeptr = &image->rowsize[row];
- image->rowstart[row] = image->rleend;
- break;
- case 3:
- sizeptr = &image->rowsize[row + channel * impYSize(image)];
- image->rowstart[row + channel * impYSize(image)] = image->rleend;
- break;
- default:
- _impReturnError(IMP_ERR_BADDIM);
- }
- if (*sizeptr != -1)
- image->wastebytes += *sizeptr;
- *sizeptr = count;
- image->rleend += count;
-
- return 0;
- }
-
-
- /**************************************************************************
- *
- * Function: rleExpandRow
- *
- * Description: Performs an adaptive RLE expansion on the specified data.
- * The function can convert between any combination of 1 and 2 byte
- * per pixel formats on input and output.
- *
- * Parameters:
- * rleBuf (I) - input RLE compressed buffer
- * ibpp (I) - input bytes per pixel
- * expBuf (O) - output expanded buffer
- * obpp (I) - output bytes per pixel
- *
- * Return: none
- *
- **************************************************************************/
-
- /* RLE expansion macro */
- /* The algorithm here is an adaptive RLE encoding. If the run
- starts with a negative count then we simply read absolute that
- count pixels. If the value is positive we duplicate the pixel
- count times. A zero count terminates the line.
- */
-
- #define EXPAND_RLE while (1) { \
- pixel = *iptr++; \
- if (!(count = (pixel & 0x7f))) \
- return; \
- if (pixel & 0x80) { \
- while (count--) \
- *optr++ = *iptr++; \
- } else { \
- pixel = *iptr++; \
- while (count--) \
- *optr++ = pixel; \
- } \
- }
-
- static void rleExpandRow(short *rleBuf, int ibpp, short *expBuf, int obpp)
- {
- register short pixel, count;
-
- /*
- * We declare the buffer pointers according to the
- * specified ibpp and obpp
- */
- if (ibpp == 1) {
- register uchar_t *iptr = (uchar_t*)rleBuf;
- if (obpp == 1) { /* ibpp == 1, obpp == 1 */
- register uchar_t *optr = (uchar_t*)expBuf;
- /* CONSTCOND */
- /* LINTED */
- EXPAND_RLE;
- } else { /* ibpp == 1, obpp == 2 */
- register short *optr = expBuf;
- /* CONSTCOND */
- EXPAND_RLE;
- }
- } else {
- register short *iptr = rleBuf;
- if (obpp == 1) { /* ibpp == 2, obpp == 1 */
- register uchar_t *optr = (uchar_t*)expBuf;
- /* CONSTCOND */
- /* LINTED */
- EXPAND_RLE;
- } else { /* ibpp == 2, obpp == 2 */
- register short *optr = expBuf;
- /* CONSTCOND */
- EXPAND_RLE;
- }
- }
- }
-
-
- /**************************************************************************
- *
- * Function: rleCompactRow
- *
- * Description: Performs an adaptive RLE compression on the specified data.
- * The function can convert between any combination of 1 and 2 byte
- * per pixel formats on input and output.
- *
- * Parameters:
- * expBuf (O) - input uncompacted buffer
- * ibpp (I) - input bytes per pixel
- * rleBuf (I) - output RLE compressed buffer
- * obpp (I) - output bytes per pixel
- * npixels (I) - number of pixels in row
- *
- * Return: Size in bytes of the compacted row.
- *
- **************************************************************************/
-
- /* RLE compression macro */
- /* The algorithm here is an adaptive RLE encoding. If the run
- starts with a negative count then we simply read absolute that
- count pixels. If the value is positive we duplicate the pixel
- count times. A zero count terminates the line.
- */
-
- #define COMPACT_RLE while (iptr < ibufend) { \
- sptr = iptr; \
- iptr += 2; \
- while ((iptr < ibufend) && \
- ((iptr[-2] != iptr[-1]) || \
- (iptr[-1] != iptr[0]))) \
- iptr++; \
- iptr -= 2; \
- count = iptr - sptr; \
- while (count) { \
- todo = (count > 126)? 126: count; \
- count -= todo; \
- *optr++ = 0x80 | todo; \
- while (todo--) \
- *optr++ = *sptr++; \
- } \
- sptr = iptr; \
- cc = *iptr++; \
- while ((iptr < ibufend) && (*iptr == cc)) \
- iptr++; \
- count = iptr - sptr; \
- while (count) { \
- todo = (count > 126)? 126: count; \
- count -= todo; \
- *optr++ = todo; \
- *optr++ = cc; \
- } \
- } \
- *optr++ = 0;
-
- static int rleCompactRow(short *expBuf, int ibpp, short *rleBuf, int obpp,
- int npixels)
- {
- register short todo, cc;
- register long count;
-
- /*
- * We declare the buffer pointers according to the
- * specified ibpp and obpp
- */
- if (ibpp == 1 && obpp == 1) {
- register uchar_t *iptr = (uchar_t*)expBuf;
- register uchar_t *ibufend = iptr + npixels;
- register uchar_t *sptr;
- register uchar_t *optr = (uchar_t*)rleBuf;
- /* LINTED */
- COMPACT_RLE;
- return optr - (uchar_t*)rleBuf;
- }
- if (ibpp == 1 && obpp == 2) {
- register uchar_t *iptr = (uchar_t*)expBuf;
- register uchar_t *ibufend = iptr + npixels;
- register uchar_t *sptr;
- register short *optr = rleBuf;
- /* LINTED */
- COMPACT_RLE;
- return optr - rleBuf;
- }
- if (ibpp == 2 && obpp == 1) {
- register short *iptr = expBuf;
- register short *ibufend = iptr + npixels;
- register short *sptr;
- register uchar_t *optr = (uchar_t*)rleBuf;
- /* LINTED */
- COMPACT_RLE;
- return optr - (uchar_t*)rleBuf;
- }
- { /* ibpp == 2 && obpp == 2 */
- register short *iptr = expBuf;
- register short *ibufend = iptr + npixels;
- register short *sptr;
- register short *optr = rleBuf;
- /* LINTED */
- COMPACT_RLE;
- return optr - rleBuf;
- }
- }
-